#include "sql/stmt/join_stmt.h"
#include "sql/stmt/filter_stmt.h"
#include "common/log/log.h"
#include "common/lang/string.h"
#include "storage/db/db.h"
#include "storage/table/table.h"
JoinStmt::~JoinStmt(){
    for (JoinUnit* unit:join_units_){
        if(unit!=nullptr)
            delete unit;
    }
    join_units_.clear();
}
JoinStmt::JoinStmt(const JoinStmt& other){
    this->join_units_.clear();
    for (JoinUnit* unit:other.join_units_){
        if(unit!=nullptr){
            JoinUnit* tmp=new JoinUnit(*unit);
            this->join_units_.push_back(tmp);
        }
    }
}
JoinStmt& JoinStmt::operator=(const JoinStmt& other){
    this->join_units_.clear();
    for (JoinUnit* unit:other.join_units_){
        if(unit!=nullptr){
            JoinUnit* tmp=new JoinUnit(*unit);
            this->join_units_.push_back(tmp);
        }
    }
    return *this;
}
JoinUnit::JoinUnit(const JoinUnit& other){
    this->table_name_=other.table_name_;
    if(other.filter_stmt_!=nullptr){
    this->filter_stmt_=new FilterStmt(*other.filter_stmt_);
    }
}
JoinUnit& JoinUnit:: operator=(const JoinUnit& other){
    this->table_name_=other.table_name_;
    if(other.filter_stmt_!=nullptr){
    this->filter_stmt_=new FilterStmt(*other.filter_stmt_);
    }
    return *this;
}
RC JoinStmt::create(Db *db, const JoinAttrSqlNode* joins,int join_num, JoinStmt *&stmt)
{  
    RC rc=RC::SUCCESS;
    stmt = nullptr;
    int size = join_num;
    if (size == 0)
    {
        stmt = nullptr;
        return RC::SUCCESS;
    }
    stmt = new JoinStmt;
    stmt->join_units_.reserve(size);
    std::vector<Table *> tables;
    std::unordered_map<std::string, Table *> table_map;
    std::vector<Field> fields;
    for (int i = 0; i < size; i++)
    {
       const JoinAttrSqlNode node = joins[i];
        const char *table_name = node.table_name.c_str();
        if (nullptr == table_name)
        {
            LOG_WARN("invalid argument. relation name is null. index=%d", i);
            return RC::INVALID_ARGUMENT;
        }
        Table *table = db->find_table(table_name);
        if (nullptr == table)
        {
            LOG_WARN("no such table. db=%s, table_name=%s", db->name(), table_name);
            return RC::SCHEMA_TABLE_NOT_EXIST;
        }
        tables.push_back(table);
        table_map.insert(std::pair<std::string, Table *>(table_name, table));
        FilterStmt* filter_stmt=nullptr;
        if(node.have_conditions){
            rc=FilterStmt::create(db,tables[0],fields,&table_map,node.conditions.data(),static_cast<int>(node.conditions.size()),filter_stmt);
        }
        if(rc!=RC::SUCCESS){
             LOG_WARN("cannot construct filter stmt");
            return rc;
        }
        JoinUnit *unit = new JoinUnit;
        unit->set_table_name(table_name);
        unit->set_filter_stmt(filter_stmt);
        stmt->join_units_.push_back(unit);
    }
    return rc;
}